package br.com.gbvbahia.mybooks.service.ws;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.PropertyInfo;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapPrimitive;
import org.ksoap2.serialization.SoapSerializationEnvelope;

import android.util.Log;
import br.com.gbvbahia.commons.ws.WSCommons;
import br.com.gbvbahia.mybooks.ActivityMae;
import br.com.gbvbahia.mybooks.R;
import br.com.gbvbahia.mybooks.dao.EditoraDAO;
import br.com.gbvbahia.mybooks.dao.LivroPrateleiraDAO;
import br.com.gbvbahia.mybooks.dao.PerfilDAO;
import br.com.gbvbahia.mybooks.dao.PrateleiraDAO;
import br.com.gbvbahia.mybooks.modelos.EditoraVO;
import br.com.gbvbahia.mybooks.modelos.LivroVO;
import br.com.gbvbahia.mybooks.modelos.PerfilVO;
import br.com.gbvbahia.mybooks.modelos.PrateleiraVO;
import br.com.gbvbahia.mybooks.modelos.RemovidoVO;
import br.com.gbvbahia.mybooks.service.model.LivroModel;
import br.com.gbvbahia.mybooks.service.model.LivrosModel;
import br.com.gbvbahia.mybooks.service.model.RemovidoModel;

class LivroService {
	private String NAMESPACE = "http://ws.bookmy.gbvbahia.com.br/";
	private String URL = WebService.URL_SERVIDOR + "/ws/livro?wsdl";

	/**
	 * Envia uma lista de livros para sincronizacao no WS
	 * 
	 * @param livros
	 * @param editoraDAO
	 * @param praDAO
	 * @param lpDAO
	 * @param perfilDAO
	 * @return
	 */
	protected static int sincronizarLivros(List<LivroVO> livros,
			EditoraDAO editoraDAO, PrateleiraDAO praDAO,
			LivroPrateleiraDAO lpDAO, PerfilDAO perfilDAO) {
		List<EditoraVO> editoras = new ArrayList<EditoraVO>(livros.size());
		List<PrateleiraVO> prateleiras = new ArrayList<PrateleiraVO>(
				livros.size());
		for (LivroVO livro : livros) {
			EditoraVO edVO = livro.getCdEditora() == null ? null : editoraDAO
					.getByID(livro.getCdEditora());
			List<String> prats = lpDAO.buscarIdPrateleiras(livro.getId(),
					praDAO.getDataBase());
			PrateleiraVO praVO = prats.isEmpty() ? null : praDAO.getByID(prats
					.get(0));
			editoras.add(edVO);
			prateleiras.add(praVO);
		}
		PerfilVO perfil = perfilDAO.getPerfil();
		if (perfil == null) {
			return WebService.SEM_PERFIL;
		}
		LivroService.SincronizarLivros livroWS = new LivroService().new SincronizarLivros();
		int ret = livroWS.sincronizarLivros(livros, editoras, prateleiras,
				perfil.getPerfil(), perfil.getId());
		if (ret == WebService.RetornosWS.SUCESSO) {
			return WebService.SINC_EFETUADA_OK;
		} else if (ret == WebService.RetornosWS.DADOS_INVALIDOS
				|| ret == WebService.RetornosWS.NEGOCIO_ERRO) {
			return WebService.SINC_DADOS_IVALIDOS;
		} else {
			return WebService.SINC_EFETUADA_ERRO;
		}
	}

	/**
	 * Envia um livro para sincronizacao no WS
	 * 
	 * @param livro
	 * @param editoraDAO
	 * @param praDAO
	 * @param lpDAO
	 * @param perfilDAO
	 * @return
	 */
	protected static int sincronizarLivro(LivroVO livro, EditoraDAO editoraDAO,
			PrateleiraDAO praDAO, LivroPrateleiraDAO lpDAO, PerfilDAO perfilDAO) {
		EditoraVO edVO = livro.getCdEditora() == null ? null : editoraDAO
				.getByID(livro.getCdEditora());
		List<String> prats = lpDAO.buscarIdPrateleiras(livro.getId(),
				praDAO.getDataBase());
		PrateleiraVO praVO = prats.isEmpty() ? null : praDAO.getByID(prats
				.get(0));
		PerfilVO perfil = perfilDAO.getPerfil();
		LivroService.SincronizarLivro livroWS = new LivroService().new SincronizarLivro();
		int ret = livroWS.sincronizarLivro(livro, edVO, praVO,
				perfil.getPerfil(), perfil.getId());
		if (ret == WebService.RetornosWS.SUCESSO) {
			return WebService.SINC_EFETUADA_OK;
		} else {
			return WebService.SINC_EFETUADA_ERRO;
		}
	}

	/**
	 * Busca todos os livros deste usuario no WS.
	 * 
	 * @param perfil
	 * @return
	 */
	protected static List<LivroModel> buscarLivros(PerfilVO perfil) {
		LivroService.BuscarLivrosPendentes lb = new LivroService().new BuscarLivrosPendentes();
		return lb.buscarLivrosPendentes(perfil.getPerfil());
	}

	/**
	 * Retorna todos os livros removidos pelo usuario no WS.
	 * 
	 * @param perfil
	 * @return
	 */
	protected static List<RemovidoModel> buscarLivrosRemovidos(PerfilVO perfil) {
		LivroService.BuscarLivrosRemovidos lr = new LivroService().new BuscarLivrosRemovidos();
		return lr.buscarLivrosRemovidos(perfil.getPerfil());
	}

	/**
	 * Envia os livros removidos do o WS. Somente livros com data remocao maior
	 * ou igual a data insercao ou atualizacao serao removidos no WS.
	 * 
	 * @param removidos
	 * @param perfil
	 * @return
	 */
	protected static int enviarRemovidos(List<RemovidoVO> removidos,
			String perfil) {
		LivroService.EnviarLivrosRemovidos le = new LivroService().new EnviarLivrosRemovidos();
		int ret = le.enviarRemovidos(removidos, perfil);
		if (ret == WebService.RetornosWS.SUCESSO) {
			return WebService.SINC_EFETUADA_OK;
		} else {
			return WebService.SINC_EFETUADA_ERRO;
		}
	}

	/**
	 * Envia os livros removidos para o WS
	 * 
	 * @author Guilherme
	 * 
	 */
	private class EnviarLivrosRemovidos extends WSCommons {
		private String METHOD_NAME = "removerLivros";
		private String SOAP_ACTION = NAMESPACE + METHOD_NAME;

		public int enviarRemovidos(List<RemovidoVO> removidos, String perfil) {
			try {
				SoapObject soap = new SoapObject(NAMESPACE, METHOD_NAME);
				SoapObject soapModel = new SoapObject(NAMESPACE,
						"removerLivros");
				int count = 0;
				for (RemovidoVO vo : removidos) {
					RemovidoModel lm = new RemovidoModel(vo.getId(),
							Long.toString(vo.getDataRemocao()));
					makeProperty(lm, "removidoModel", soap, lm.getClass());
					count++;
				}
				soap.addSoapObject(soapModel);
				makeProperty("sal", "sal", soap, PropertyInfo.STRING_CLASS);
				makeProperty(perfil, "perfil", soap, PropertyInfo.STRING_CLASS);
				SoapSerializationEnvelope envelope = getEnvelope(
						SoapEnvelope.VER11, soap, URL, SOAP_ACTION);
				SoapPrimitive resultsRequestSOAP = (SoapPrimitive) envelope
						.getResponse();
				Log.d(ActivityMae.LOG_TAG, resultsRequestSOAP.toString());
				return Integer.valueOf(resultsRequestSOAP.toString());
			} catch (Exception e) {
				Log.e(ActivityMae.LOG_TAG, "Erro LivroWS:", e);
				return WebService.ERRO_DESCONHECIDO;
			}
		}
	}

	/**
	 * Classe de conexao com web service
	 * 
	 * @author Guilherme
	 * 
	 */
	private class SincronizarLivro extends WSCommons {
		private String METHOD_NAME = "sincronizarLivro";
		private String SOAP_ACTION = NAMESPACE + METHOD_NAME;

		public int sincronizarLivro(LivroVO livro, EditoraVO editora,
				PrateleiraVO prateleira, String perfil, String idPerfilMobile) {
			try {
				SoapObject soap = new SoapObject(NAMESPACE, METHOD_NAME);
				LivroModel lm = new LivroModel(livro, editora, prateleira,
						perfil, idPerfilMobile);
				makeProperty(lm, "livroModel", soap, PropertyInfo.OBJECT_CLASS);
				makeProperty("sal", "sal", soap, PropertyInfo.STRING_CLASS);
				SoapSerializationEnvelope envelope = getEnvelope(
						SoapEnvelope.VER11, soap, URL, SOAP_ACTION);
				SoapPrimitive resultsRequestSOAP = (SoapPrimitive) envelope
						.getResponse();
				Log.d(ActivityMae.LOG_TAG, resultsRequestSOAP.toString());
				return R.string.naoImplementado;
			} catch (Exception e) {
				Log.e(ActivityMae.LOG_TAG, "Erro LivroWS:", e);
				return WebService.ERRO_DESCONHECIDO;
			}
		}
	}

	/**
	 * Classe de conexao com web service
	 * 
	 * @author Guilherme
	 * 
	 */
	private class SincronizarLivros extends WSCommons {
		private String METHOD_NAME = "sincronizarLivros";
		private String SOAP_ACTION = NAMESPACE + METHOD_NAME;

		public int sincronizarLivros(List<LivroVO> livros,
				List<EditoraVO> editora, List<PrateleiraVO> prateleira,
				String perfil, String idPerfilMobile) {
			try {
				SoapObject soap = new SoapObject(NAMESPACE, METHOD_NAME);
				SoapObject soapModel = new SoapObject(NAMESPACE, "livroModelo");
				int count = 0;
				for (LivroVO livro : livros) {
					LivroModel lm = new LivroModel(livro, editora.get(count),
							prateleira.get(count), perfil, idPerfilMobile);
					makeProperty(lm, "livrosModel", soap, lm.getClass());
					count++;
				}
				soap.addSoapObject(soapModel);
				makeProperty("sal", "sal", soap, PropertyInfo.STRING_CLASS);
				SoapSerializationEnvelope envelope = getEnvelope(
						SoapEnvelope.VER11, soap, URL, SOAP_ACTION);
				SoapPrimitive resultsRequestSOAP = (SoapPrimitive) envelope
						.getResponse();
				Log.d(ActivityMae.LOG_TAG, resultsRequestSOAP.toString());
				return Integer.valueOf(resultsRequestSOAP.toString());
			} catch (Exception e) {
				Log.e(ActivityMae.LOG_TAG, "Erro LivroWS:", e);
				return WebService.ERRO_DESCONHECIDO;
			}
		}
	}

	/**
	 * Busca os livros removidos na nuvem pelo usuario
	 * 
	 * @author Guilherme
	 * 
	 */
	private class BuscarLivrosRemovidos extends WSCommons {
		private String METHOD_NAME = "buscarLivrosRemovidos";
		private String SOAP_ACTION = NAMESPACE + METHOD_NAME;

		public List<RemovidoModel> buscarLivrosRemovidos(String perfil) {
			try {
				SoapObject soap = new SoapObject(NAMESPACE, METHOD_NAME);
				makeProperty("sal", "sal", soap, PropertyInfo.STRING_CLASS);
				makeProperty(perfil, "perfil", soap, PropertyInfo.STRING_CLASS);
				SoapSerializationEnvelope envelope = getEnvelope(
						SoapEnvelope.VER11, soap, URL, SOAP_ACTION);
				SoapObject resp = (SoapObject) envelope.bodyIn;
				int propriedades = resp.getPropertyCount();
				List<RemovidoModel> toReturn = new ArrayList<RemovidoModel>();
				for (int i = 0; i < propriedades; i++) {
					SoapObject obj = (SoapObject) resp.getProperty(i);
					if (obj == null) {
						continue;
					}
					RemovidoModel removidoModel = getRemovidoModel(obj);
					if (removidoModel != null)
						toReturn.add(removidoModel);
				}
				return toReturn;
			} catch (Exception e) {
				Log.e(ActivityMae.LOG_TAG, "Erro LivroWS:", e);
				// ERRO DESCONHECIDO
				throw new RuntimeException(e);
			}
		}

		private RemovidoModel getRemovidoModel(SoapObject obj) {
			String encoding = "utf-8";
			try {
				String idLivroRemovido = getString(obj, encoding,
						"idLivroMobile");
				String dataRemovido = getString(obj, encoding, "dataRemocao");
				RemovidoModel toReturn = new RemovidoModel();
				if (StringUtils.isBlank(idLivroRemovido)
						|| StringUtils.isBlank(dataRemovido)) {
					return null;
				}
				toReturn.setIdLivroRemovido(idLivroRemovido);
				toReturn.setDataRemocao(dataRemovido);
				Log.i(ActivityMae.LOG_TAG, "idLivroRemovido: "
						+ idLivroRemovido);
				Log.i(ActivityMae.LOG_TAG, "dataRemovido: " + dataRemovido);
				return toReturn;
			} catch (Exception e) {
				Log.e(ActivityMae.LOG_TAG, "ERRO: getRemovidoModel", e);
				return null;
			}
		}
	}

	private class BuscarLivrosPendentes extends WSCommons {
		private String METHOD_NAME = "buscarLivrosPendentes";
		private String SOAP_ACTION = NAMESPACE + METHOD_NAME;

		public List<LivroModel> buscarLivrosPendentes(String perfil) {
			try {
				SoapObject soap = new SoapObject(NAMESPACE, METHOD_NAME);
				makeProperty("sal", "sal", soap, PropertyInfo.STRING_CLASS);
				makeProperty(perfil, "perfil", soap, PropertyInfo.STRING_CLASS);
				SoapSerializationEnvelope envelope = getEnvelope(
						SoapEnvelope.VER11, soap, URL, SOAP_ACTION);
				SoapObject resp = (SoapObject) envelope.bodyIn;
				int propriedades = resp.getPropertyCount();
				List<LivroModel> toReturn = new ArrayList<LivroModel>();
				for (int i = 0; i < propriedades; i++) {
					SoapObject obj = (SoapObject) resp.getProperty(i);
					if (obj == null) {
						continue;
					}
					LivroModel livroModel = getLivroModel(obj);
					if (livroModel != null)
						toReturn.add(livroModel);
				}
				return toReturn;
			} catch (Exception e) {
				Log.e(ActivityMae.LOG_TAG, "Erro LivroWS:", e);
				// ERRO DESCONHECIDO
				throw new RuntimeException(e);
			}
		}

		private LivroModel getLivroModel(SoapObject obj) {
			String encoding = "utf-8";
			try {
				LivroModel toReturn = new LivroModel();
				if (obj.hasProperty("nomeLivro")) {
					String nomeLivro = getString(obj, encoding, "nomeLivro");
					toReturn.setNomeLivro(nomeLivro);
					Log.i(ActivityMae.LOG_TAG, "nomeLivro: " + nomeLivro);
					if (StringUtils.isBlank(nomeLivro)) {
						return null;
					}
				}
				if (obj.hasProperty("autorLivro")) {
					String autor = getString(obj, encoding, "autorLivro");
					toReturn.setAutorLivro(autor);
					Log.i(ActivityMae.LOG_TAG, "autorLivro: " + autor);
				}
				if (obj.hasProperty("edicao")) {
					String edicao = getString(obj, encoding, "edicao");
					toReturn.setEdicao(edicao);
					Log.i(ActivityMae.LOG_TAG, "edicao: " + edicao);
				}
				if (obj.hasProperty("editoraNome")) {
					String editora = getString(obj, encoding, "editoraNome");
					toReturn.setEditoraNome(editora);
					Log.i(ActivityMae.LOG_TAG, "editoraNome: " + editora);
				}
				if (obj.hasProperty("prateleiras")) {
					String prateleira = getString(obj, encoding, "prateleiras");
					toReturn.setPrateleiras(prateleira);
					Log.i(ActivityMae.LOG_TAG, "prateleiras: " + prateleira);
				}
				if (obj.hasProperty("isbn")) {
					String isbn = getString(obj, encoding, "isbn");
					toReturn.setIsbn(isbn);
					Log.i(ActivityMae.LOG_TAG, "isbn: " + isbn);
				}
				if (obj.hasProperty("statusLivro")) {
					String statusLivro = getString(obj, encoding, "statusLivro");
					toReturn.setStatusLivro(statusLivro);
					Log.i(ActivityMae.LOG_TAG, "statusLivro: " + statusLivro);
				}
				if (obj.hasProperty("tipoLivro")) {
					String tipoLivro = getString(obj, encoding, "tipoLivro");
					toReturn.setTipoLivro(tipoLivro);
					Log.i(ActivityMae.LOG_TAG, "tipoLivro: " + tipoLivro);
				}
				if (obj.hasProperty("descricao")) {
					String descricao = getString(obj, encoding, "descricao");
					toReturn.setDescricao(descricao);
					Log.i(ActivityMae.LOG_TAG, "descricao: " + descricao);
				}
				if (obj.hasProperty("avaliacao")) {
					String avaliacao = getString(obj, encoding, "avaliacao");
					toReturn.setAvaliacao(avaliacao);
					Log.i(ActivityMae.LOG_TAG, "avaliacao: " + avaliacao);
				}
				if (obj.hasProperty("nota")) {
					String nota = getString(obj, encoding, "nota");
					toReturn.setNota(nota);
					Log.i(ActivityMae.LOG_TAG, "nota: " + nota);
				}
				if (obj.hasProperty("recomendado")) {
					String recomendado = getString(obj, encoding, "recomendado");
					toReturn.setRecomendado(recomendado);
					Log.i(ActivityMae.LOG_TAG, "recomendado: " + recomendado);
				}
				if (obj.hasProperty("dataAlteracao")) {
					String dataAlteracao = getString(obj, encoding, "dataAlteracao");
					toReturn.setDataAlteracao(dataAlteracao);
					Log.i(ActivityMae.LOG_TAG, "dataAlteracao: " + dataAlteracao);
				}
				if (obj.hasProperty("idMobile")) {
					String idMobile = getString(obj, encoding, "idMobile");
					toReturn.setIdMobile(idMobile);
					Log.i(ActivityMae.LOG_TAG, "idMobile: " + idMobile);
				}
				if (obj.hasProperty("idPerfilMobile")) {
					String idPerfilMobile = getString(obj, encoding, "idPerfilMobile");
					toReturn.setIdPerfilMobile(idPerfilMobile);
					Log.i(ActivityMae.LOG_TAG, "idPerfilMobile: " + idPerfilMobile);
				}
				if (obj.hasProperty("ano")) {
					String ano = getString(obj, encoding, "ano");
					toReturn.setAno(ano);
					Log.i(ActivityMae.LOG_TAG, "ano: " + ano);
				}
				if (obj.hasProperty("perfil")) {
					String perfil = getString(obj, encoding, "perfil");
					toReturn.setPerfil(perfil);
					Log.i(ActivityMae.LOG_TAG, "perfil: " + perfil);
				}
				if (obj.hasProperty("pratPublica")) {
					String pratPublica = getString(obj, encoding, "pratPublica");
					toReturn.setPratPublica(pratPublica);
					Log.i(ActivityMae.LOG_TAG, "perfil: " + pratPublica);
				}
				if (obj.hasProperty("idEditoraMobile")) {
					String idEditoraMobile = getString(obj, encoding, "idEditoraMobile");
					toReturn.setIdEditoraMobile(idEditoraMobile);
					Log.i(ActivityMae.LOG_TAG, "idEditoraMobile: " + idEditoraMobile);
				}
				if (obj.hasProperty("idPrateleiraMobile")) {
					String idPrateleiraMobile = getString(obj, encoding, "idPrateleiraMobile");
					toReturn.setIdPrateleiraMobile(idPrateleiraMobile);
					Log.i(ActivityMae.LOG_TAG, "idPrateleiraMobile: " + idPrateleiraMobile);
				}
				if (obj.hasProperty("dataAlteracaoPrateleira")) {
					String dataAlteracaoPrateleira = getString(obj, encoding, "dataAlteracaoPrateleira");
					toReturn.setDataAlteracaoPrateleira(dataAlteracaoPrateleira);
					Log.i(ActivityMae.LOG_TAG, "idPrateleiraMobile: " + dataAlteracaoPrateleira);
				}
				if (obj.hasProperty("dataAlteracaoEditora")) {
					String dataAlteracaoEditora = getString(obj, encoding, "dataAlteracaoEditora");
					toReturn.setDataAlteracaoEditora(dataAlteracaoEditora);
					Log.i(ActivityMae.LOG_TAG, "idPrateleiraMobile: " + dataAlteracaoEditora);
				}
				return toReturn;
			} catch (Exception e) {
				Log.e(ActivityMae.LOG_TAG, "ERRO: getLivroModel", e);
				return null;
			}
		}

	}

	/**
	 * @param obj
	 * @param encoding
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	private String getString(SoapObject obj, String encoding,
			String propertieName) throws UnsupportedEncodingException {
		if (obj.getProperty(propertieName) == null) {
			return null;
		}
		String propertie = obj.getProperty(propertieName).toString();
		return StringUtils.toString(propertie.toString().getBytes(), encoding);
	}
}
